from abc import ABC, abstractmethod
from typing import List, AsyncGenerator, Union, Optional

from axiom_boot.scraper.models import Target, Response, Item


class Downloader(ABC):
    """下载器接口，负责执行网络请求并返回响应。"""

    @abstractmethod
    async def download(self, target: Target) -> Response:
        """
        根据给定的目标下载内容。

        Args:
            target: 爬取目标。

        Returns:
            一个包含响应内容的 Response 对象。
        """
        pass


class Extractor(ABC):
    """提取器接口，负责从响应中解析和提取数据。"""

    @abstractmethod
    def extract(self, response: Response) -> List[Item]:
        """
        从 Response 对象中提取结构化的 Item。

        Args:
            response: 下载器返回的响应对象。

        Returns:
            一个包含 Item 实例的列表。如果未提取到任何数据，则返回空列表。
        """
        pass


class ItemPipeline(ABC):
    """Item 处理管道接口，负责处理由 Extractor 提取出的 Item。"""

    @abstractmethod
    async def process_item(self, item: Item, target: Target) -> Item:
        """
        处理单个 Item。
        此方法可以修改 Item、将其存储到数据库或文件系统，或抛出 DropItem 异常来丢弃它。

        Args:
            item: 从提取器传入的 Item。
            target: 发出此请求的原始 Target 对象。

        Returns:
            处理后的 Item，它将被传递给下一个管道。
        """
        pass


class ScraperMiddleware(ABC):
    """爬虫中间件接口，允许挂接到请求和响应的处理流程中。"""

    @abstractmethod
    async def process_request(self, target: Target) -> Optional[Union[Target, Response]]:
        """
        在下载请求发出前处理 Target。
        - 返回 Target: 继续处理，并将此返回的 Target 传递给下一个中间件。
        - 返回 Response: 终止请求，直接将此 Response 传递给响应处理流程。
        - 返回 None: 中止对此 Target 的处理。
        """
        return target

    @abstractmethod
    async def process_response(self, target: Target, response: Response) -> Optional[Union[Target, Response]]:
        """
        在下载请求完成后处理 Response。
        - 返回 Response: 继续处理，并将此返回的 Response 传递给下一个中间件。
        - 返回 Target: 重新发起请求，将此返回的 Target 放入调度队列。
        - 返回 None: 中止对此 Response 的处理。
        """
        return response

    @abstractmethod
    async def process_exception(self, target: Target, exception: Exception) -> Optional[Union[Target, Response]]:
        """
        在处理过程中发生异常时调用。
        - 返回 Target: 重新发起请求，将此返回的 Target 放入调度队列。
        - 返回 Response: 忽略异常，将此返回的 Response 送往响应处理流程。
        - 返回 None: 继续将异常向上传播。
        """
        return None 